package com.xplay.xpocker.observer;

import com.baomidou.mybatisplus.core.toolkit.Sequence;
import com.xplay.xpocker.constant.MessageNoticeEnum;
import com.xplay.xpocker.core.lock.LocalLockServer;
import com.xplay.xpocker.room.message.MessageContent;
import io.netty.channel.ChannelHandlerContext;
import lombok.Data;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.IdGenerator;

import java.math.BigDecimal;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author wanjie
 * @date 2021/3/22 17:10
 */
@Data
public class SubscriptionSubject implements Subject {

    private static Logger log = LoggerFactory.getLogger(SubscriptionSubject.class);
    // 存储桌面上的所有玩家
    private ConcurrentHashMap<BigDecimal, ChannelHandlerContext> subjectUsers = null;

    private long sourceId = 0;


    public SubscriptionSubject() {
        Sequence sequence = new Sequence(1, 1);
        sourceId = sequence.nextId();
        subjectUsers = new ConcurrentHashMap<>();
    }

    /**
     * 注意这里因为前端短线重连  会导致并发连接，这里使用LocalLockServer 同一用户  同一 时间  只有一个加入订阅对象
     * 用户端只会存在一个连接  因为是单例模式
     * 但是如果出现瞬时连接多个 这里会出现多线程问题，将正常的连接给close掉了，留下了不正常的连接
     * 但是心跳 会一直发送消息  所以这里做一个hashcode 的判断
     * 用心跳的 channel 去替换掉  订阅模式中的  channel
     *
     * @param observer
     * @TODO 多线程问题  暂时没有什么好的解决方案
     */

    @Override
    public void attach(ChannelHandlerContext observer) {
        BigDecimal userId = ChannelHandlerManager.getUserId(observer);
        LocalLockServer.getInstance().lock(String.format("USER_ADD_ROOM_%s", userId), () -> {
            ChannelHandlerContext before = subjectUsers.computeIfPresent(userId, (k, v) -> {
                if (v.hashCode() != observer.hashCode()) {
                    log.info("用户:{},产生了重复连接,KILL OLD:{}", userId, v.hashCode());
                    v.channel().close();
                    return observer;
                }
                return observer;
            });
            if (before == null) {
                subjectUsers.put(userId, observer);
            }
            return true;
        });

    }


    @Override
    public void detach(ChannelHandlerContext observer) {
       /* Iterator<ChannelHandlerContext> iterator = subjectUsers.iterator();
        if (iterator.hasNext()) {
            if (getUserId(iterator.next()).equals(getUserId(observer))) {
                iterator.remove();
            }
        }*/
    }


    @Override
    public <T> void notifyMessage(MessageContent<T> content) {
        if (subjectUsers.size() == 0) {
            return;
        }
        for (Map.Entry<BigDecimal, ChannelHandlerContext> entry : subjectUsers.entrySet()) {
            if (content.getMnEnum().equals(MessageNoticeEnum.ALL)) {
                // 发送给所有
                ChannelHandlerManager.getInstance().senMessage(entry.getValue(), content);
            } else if (content.getMnEnum().equals(MessageNoticeEnum.CURRENT) && null != content.getMessageToUid() && entry.getKey().equals(content.getMessageToUid())) {
                // 发送给当前
                ChannelHandlerManager.getInstance().senMessage(entry.getValue(), content);
            } else if (content.getMnEnum().equals(MessageNoticeEnum.OTHER) && null != content.getMessageToUid() && !entry.getKey().equals(content.getMessageToUid())) {
                // 发送给其它人
                ChannelHandlerManager.getInstance().senMessage(entry.getValue(), content);
            }
        }
    }


}
